#include "core/main.h"

// Create an "empty" GLTexture with no image data. You will need
// to load an image before you can use this texture for
// rendering.
GLTexture::GLTexture()
    : _width(-1)
    , _height(-1)
{
    Initialize();
}

// Create a new GLTexture using the pixel data from the given
// image (which will be copied in). Use the options to specify
// whether mip maps should be generated.
GLTexture::GLTexture(
    const Bitmap &bmp,
    ImageOptions options)
    : _width(-1)
    , _height(-1)
{
    Initialize();
    LoadImageData(bmp, options);
}

// Common initialization code, used by all constructors.
void GLTexture::Initialize()
{
    _texId = 0;
    glGenTextures(1, &_texId);

    // Default filtering and addressing options:
    SetFilter(GL_LINEAR, GL_LINEAR);
    SetWrap(GL_CLAMP, GL_CLAMP);
}


// Delete an existing GLTexture.
GLTexture::~GLTexture()
{
    glDeleteTextures(1, &_texId);
}

// Load image data into the GLTexture. The texture will be
// resized to match the image as needed. Use the options
// to specify whether mip maps should be generated.
void GLTexture::LoadImageData(const Bitmap &bmp,
                              ImageOptions options)
{
    Bind();

    int width = bmp.Width();
    int height = bmp.Height();
    _width = width;
    _height = height;
    const RGBColor* pixels = bmp.Pixels();

    if (options & kGenerateMipmaps) {
        gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA,
                          width, height,
                          GL_RGBA, GL_UNSIGNED_BYTE, pixels);
    }
    else {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
                     width, height, 0,
                     GL_RGBA, GL_UNSIGNED_BYTE, pixels);
    }
    UnBind();
}

// Bind this texture for use in subsequent OpenGL drawing.
void GLTexture::Bind()
{
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, _texId);
}

// Un-bind this texture and return to untextured drawing.
void GLTexture::UnBind()
{
    glBindTexture(GL_TEXTURE_2D, 0);
    glDisable(GL_TEXTURE_2D);
}

// Set the OpenGL texture-filtering mode to use for texture
// magnification and minification respectively.
void GLTexture::SetFilter(GLint magFilter, GLint minFilter)
{
    Bind();
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
    UnBind();
}

// Set the OpenGL mode to use for texture addressing in
// the S and T dimensions respectively.
void GLTexture::SetWrap(GLint wrapS, GLint wrapT)
{
    Bind();
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
    UnBind();
}
